#pragma once
#ifndef __POLL_SVR_H__
#define __POLL_SVR_H__

#include <iostream>
#include <string>
#include <vector>
#include <poll.h>
#include <sys/time.h>
#include "log.hpp"
#include "Sock.hpp"

#define FD_NONE -1

using namespace std;

class PollServer
{
public:
    static const int nfds=100;
    PollServer(const uint16_t &port=8080)
        :_port(port)
        ,_nfds(nfds)
        ,_timeout(1000)
    {
        _listensock=Sock::Socket();
        Sock::Bind(_listensock,_port);//ip缺省值为 0.0.0.0
        Sock::Listen(_listensock);
        logMessage(DEBUG,"%s","create base socket success");
        _fds=new struct pollfd[_nfds];
        for(int i=0;i<_nfds;i++)
        {
            _fds[i].fd=FD_NONE;
            _fds[i].events=_fds[i].revents=0;

        }
        //做一个规定 _fd_array[0]=_listensock
        _fds[0].fd=_listensock;
        _fds[0].events=POLLIN;

    }
    void Start()
    {
        while(true)
        {
            int n=poll(_fds,_nfds,_timeout);
            switch(n)
            {   
            case 0:
                logMessage(DEBUG,"time out...");
                break;
            case -1:  
                logMessage(WARNING,"poll errno: %d : %s",errno,strerror(errno));
                break;
            default:
                //成功
                HandlerEvent();
                break;  
            }
        }
    }
    ~PollServer()
    {
        if(_listensock>=0) close(_listensock);
        if(_fds) delete[] _fds;
    }

private:
    void HandlerEvent()
    {
        for(int i=0;i<_nfds;i++)
        {
            //没让select关心这个文件
            if(_fds[i].fd==FD_NONE) continue; 

            //让关心了 但是需要知道他是否就绪
            if(_fds[i].revents & POLLIN)
            {
                if(_fds[i].fd==_listensock)
                {
                    Acceptr();
                }
                else
                {
                    Recver(i);
                }
            }
        }
    }
    void Acceptr()
    {
        string clientip;
        uint16_t clientport=0;
        int sock=Sock::Accept(_listensock,&clientip,&clientport);
        if(sock<0)
        {
            logMessage(WARNING,"accept error");
            return;
        }
        logMessage(DEBUG,"get a new link success :[%s:%d] : %d",clientip.c_str(),clientport,sock);

        //找一个位置添加 我刚刚得到的sock套接字 好让select帮我关心
        int pos=1;
        for(;pos<_nfds;pos++)
        {
            if(_fds[pos].fd==FD_NONE) break;
        }
        if(pos==_nfds)
        {
            //也可以在这里扩容
            logMessage(WARNING,"%s:%d","select server already full,close fd: %d",sock);
            close(sock);
        }
        else
        {
            _fds[pos].fd=sock;
            _fds[pos].events=POLLIN;
        }
    
    }
    void Recver(int pos)
    {
        // 读事件就绪：INPUT事件到来、recv，read
        logMessage(DEBUG, "message in, get IO event: %d", _fds[pos].fd);
        // 暂时先不做封装, 此时select已经帮我们进行了事件检测，fd上的数据一定是就绪的，即 本次 不会被阻塞
        // 这样读取有bug吗？有的，你怎么保证以读到了一个完整包文呢？
        char buffer[1024];
        int n = recv(_fds[pos].fd, buffer, sizeof(buffer)-1, 0);
        if(n > 0)
        {
            buffer[n] = 0;
            logMessage(DEBUG, "client[%d]# %s", _fds[pos].fd, buffer);
        }
        else if(n == 0)
        {
            logMessage(DEBUG, "client[%d] quit, me too...", _fds[pos].fd);
            // 1. 我们也要关闭不需要的fd
            close(_fds[pos].fd);
            // 2. 不要让poll帮我关心当前的fd了
            _fds[pos].fd = FD_NONE;
            _fds[pos].events=0;
        }
        else
        {
            logMessage(WARNING, "%d sock recv error, %d : %s", _fds[pos].fd, errno, strerror(errno));
            // 1. 我们也要关闭不需要的fd
            close(_fds[pos].fd);
            // 2. 不要让select帮我关心当前的fd了
           _fds[pos].fd = FD_NONE;
        }
    }
private:
    uint16_t _port;
    int _listensock;
    struct pollfd* _fds;
    int _nfds;//最大数量
    int _timeout;


};

#endif
